package com.king.juc.n8.threadpooldemo.threadpool;

import lombok.extern.slf4j.Slf4j;

import java.util.HashSet;
import java.util.concurrent.TimeUnit;

/**
 * @author king
 * @date 2020/12/7 22:56
 */
@Slf4j(topic = "c.ThreadPool")
public class ThreadPool {
    /**
     * 任务队列
     */
    private BlockingQueue<Runnable> taskQueue;

    /**
     * 线程集合
     */
    private HashSet<Worker> workers = new HashSet<>();

    /**
     * 核心线程数
     */
    private int coreSize;

    /**
     * 获取任务的超时时间
     */
    private long timeout;
    private TimeUnit timeUnit;
    /**
     * 执行策略
     */
    private RejectPolicy rejectPolicy;

    /**
     * 执行任务
     */
    public void execute(Runnable task){
        synchronized (workers) {
            // 当任务数没有超过 coreSize 时, 直接交给 worker 对象执行
            if (workers.size() < coreSize){
                Worker worker = new Worker(task);
                log.debug("新增 worker {}", worker);
                workers.add(worker);
                worker.start();
            }else{
                // 如果任务数超过 coreSize 时, 加入任务队列等待
//                taskQueue.put(task);

                // 队列满时的自定义操作
                taskQueue.tryPut(rejectPolicy, task);
            }
        }
    }

    public ThreadPool(int capcity, int coreSize, long timeout, TimeUnit timeUnit, RejectPolicy<Runnable> rejectPolicy) {
        this.taskQueue = new BlockingQueue<>(capcity);
        this.coreSize = coreSize;
        this.timeout = timeout;
        this.timeUnit = timeUnit;
        this.rejectPolicy = rejectPolicy;
    }

    class Worker extends Thread {

        private Runnable task;

        public Worker(Runnable task) {
            this.task = task;
        }

        @Override
        public void run() {
            // 执行任务
            // 1) 当 task 不为空, 执行任务
            // 2) 当 task 执行完毕, 再接着从任务队列获取任务并执行
//            while(task != null || (task = taskQueue.take()) != null){
            // 限时等待
            while(task != null || (task = taskQueue.poll(timeout, timeUnit)) != null){
                try {
                    log.debug("正在执行....{}", task);
                    task.run();
                }catch (Exception e){
                    e.printStackTrace();
                }finally {
                    task = null;
                }
            }

            synchronized (workers){
                log.debug("worker 被移除 {}", this);
                workers.remove(this);
            }
        }
    }
}
